#include <dspSimulator/instruction/subc.h>


bool SUBC::checkCondition(std::shared_ptr<DspMachine> dspMachine) {
    return checkStandardCondition(dspMachine);
}

void SUBC::loadInstIRIntoJit(llvm::LLVMContext *llvmContext, llvm::Module *module,
                             std::shared_ptr<llvm::IRBuilder<>> irBuilder) {

}

std::shared_ptr<Instruction> SUBC::decode(std::shared_ptr<InstInfo> instInfo, u64 baseCycle) {
    std::shared_ptr<SUBC> subc;
    auto dspInstInfo = std::dynamic_pointer_cast<DspInstInfo>(instInfo);
    bool isStandardInst = dspInstInfo->isStandardInstruction();
    if (isStandardInst) {
        auto data = vectorToBitSet<32>(dspInstInfo->getBits());
        if (checkBits<10>(data, 2, 0b1001011110) && existStandardCondition(data)) {
            subc = std::make_shared<SUBC>(dspInstInfo->getAddress(), baseCycle);
            subc->creg_z = extractBits<4>(data, 28);
            subc->dst = extractBits<5>(data, 23).to_ulong();
            subc->src2 = extractBits<5>(data, 18).to_ulong();
            subc->src1 = extractBits<5>(data, 13).to_ulong();
            subc->x = data[12];
            subc->s = data[1];
            subc->p = data[0];
            if (subc->s == 0) {
                subc->funcUnit = FuncUnit::L1;
            } else {
                subc->funcUnit = FuncUnit::L2;
            }
            subc->instFormat = InstFormat::Kind1;
        }
    }
    return subc;
}

void SUBC::executeCustom(std::shared_ptr<TargetMachine> targetMachine, ExecutePhase executePhase) {
    u32 src1 = *src1LoRegPtr;
    u32 src2 = *src2LoRegPtr;
    if (src1 - src2 >= 0) {
        *dstLoRegPtr = ((src1 - src2) << 1) + 1;
    } else {
        *dstLoRegPtr = (src1 << 1);
    }
}

std::string SUBC::toString() const {
    std::string res;
    res = getStandardConditionString() + " " + m_name + " " + FuncUnitName[static_cast<u32>(funcUnit)] + " "
          + getSrc1Reg32Name() + "," + getSrc2Reg32Name() + "," + getDstReg32Name();
    return res;
}

std::shared_ptr<DspInstruction> SUBC::clone() {
    return std::make_shared<SUBC>(*this);
}
